/**
 * 
 */
package org.stars.daostars;

import java.sql.Connection;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.stars.daostars.core.DaoStars;
import org.stars.database.ConnectionPoolManager;
import org.stars.util.StringUtility;
import org.stars.util.reflect.BeanUtil;
import org.stars.util.reflect.Getter;


/**
 * Classe di utilita'a' per l'accesso alla base dati.
 * 
 * @author Francesco Benincasa (908099)
 * @since 23 maggio 2007
 */
public class DaoUtility {
	
	/**
	 * Recupera dato un Dao ed una query la classe che rappresenta quest'ultima. Il nome 
	 * del dao deve corrispondere alla definizione dello stesso. Ad esempio, se un dao
	 * e' definito nel file <code>DaoFunction.xml</code>, per recuperare le query di tale 
	 * definizione occorrera' passare come primo parametro <code>DaoFunction</code>.
	 * 
	 * Nel caso la query non esiste, viene restituito un oggetto nullo.
	 * 
	 * @param sDao
	 * 		nome del dao completo (ad esempio <code>DaoFunction</code>). 
	 * @param sQueryName
	 * 		nome della query da ottenere
	 * @return
	 * 		codice sql della query o stringa vuota
	 */
	public static String getQuerySql(String sDao,String sQueryName)
	{
		return DaoStars.getInstance().getQuerySql(sDao, sQueryName);
	}

	
	/**
	 * Data una classe che rappresenta un Dao o un EntityBean, viene recuperata
	 * la query il cui nome viene specificato come parametro. Ad esempio, se un dao
	 * e' definito nel file <code>DaoFunction.xml</code>, per recuperare le query di tale 
	 * definizione occorrer� passare come primo parametro una classe dal nome <code>DaoFunction</code> 
	 * o <code>EbFunction</code>.
	 * 
	 * @param theClass
	 * 			classe che rappresenta il dao
	 * @param sQueryName
	 * 			nome della query
	 * @return
	 * 			codice sql della query o stringa vuota
	 */
	public static String getQuerySql(Class<?> theClass, String sQueryName)
	{
		return DaoStars.getInstance().getQuerySql(theClass, sQueryName);
	}
	
	/**
	 * Restituisce la connessione di default dell'applicazione.
	 * 
	 * @return
	 * 		connessione
	 * @throws Exception
	 * 		in caso di errore
	 */
	public static Connection getConnection() throws Exception {
		return ConnectionPoolManager.getInstance().getConnection();
	}
	
	/**
	 * Restituisce una connessione associata ad un connection pool il cui nome
	 * è passato come parametro.
	 * 
	 * Il nome del connection pool deve corrispondere al nome definito nel file
	 * <code>connection.xml</code>
	 * 
	 * @param connectionName
	 * 			nome del connection pool.
	 * @return
	 * 			connessione
	 * @throws Exception
	 * 			in caso di errore.
	 */
	public static Connection getConnection(String connectionName) throws Exception {
		return ConnectionPoolManager.getInstance().getConnection(connectionName);
	}
	
	     
    /**
     * Dato un entitybean ed un array di nomi di attributi, questo metodo 
     * restituisce il set di attributi che rientrano nell'array e che esistono
     * nell'entity bean. Questo metodo risulta essere utile nel caso in cui
     * si vogliano conoscere i campi di un eb valorizzati dopo una query.
     * <p>
     * Tipicamente l'array viene ricavato dal metodo getColumns del dao.
     * 
     * @param eb 
     *		entity bean su cui fare 
     * @param cols
     * 		array di colonne
     * @return
     * 		set di colonne valorizzate. Tutti i campi sono messi in lowercase.
     * @throws Exception
     * 		in caso di errore
     */
    public static Set<String> getFilledPropertiesSet(Object eb, String[] cols) throws Exception {    	
    	TreeSet<String> colSet=new TreeSet<String>();
    	
    	if (eb==null || cols==null) return colSet;
    	
    	for(String app: cols)
    	{
    		colSet.add(app.toUpperCase());
    	}    	    	
    	Map<String, Getter> getters=BeanUtil.getGetters(eb);
    	
    	TreeSet<String> found=new TreeSet<String>();
    	
    	for (Getter item:getters.values())
    	{
    		String app=item.getPropertyName().toUpperCase();
    		
    		if (colSet.contains(app))
    		{
    			found.add(app.toUpperCase());
    			colSet.remove(app);
    		}
    	}

        return found;
    }
    
    /**
     * Dato un entitybean ed un array di nomi di attributi, questo metodo 
     * restituisce il set di attributi che rientrano nell'array e che esistono
     * nell'entity bean. Questo metodo risulta essere utile nel caso in cui
     * si vogliano conoscere i campi di un eb valorizzati dopo una query.
     * <p>
     * Tipicamente l'array viene ricavato dal metodo getColumns del dao.
     * <p>
     * Il terzo parametro da la possibilità di escludere un elenco di colonne.
     * 
     * @param eb 
     *		entity bean su cui fare 
     * @param cols
     * 		array di colonne
     * @param colsToExclude
     * 		colonne da escludere
     * @return
     * 		set di colonne valorizzate. Tutti i campi sono messi in lowercase.
     * @throws Exception
     * 		in caso di errore
     */
    public static Set<String> getFilledPropertiesSet(Object eb, String[] cols, String[] colsToExclude) throws Exception {    	
    	Set<String> colSet=getFilledPropertiesSet(eb, cols);
    	    	
    	for(String app: colsToExclude)
    	{
    		app=StringUtility.nvl(app).toUpperCase();
    		
    		if (colSet.contains(app))
    		{
    			colSet.remove(app);
    		}    		
    	}    	    	    	    
        return colSet;
    }
    
    /**
     * Dati due entity bean, uno chiamato <code>main</code> ed uno chiamato <code>newValues</code>,
     * questo metodo prende gli attributi i cui nomi sono definiti nel parametro <code>cols</code>
     * dall'entity bean <code>newValues</code> e li inserisce nell'entity bean <code>main</code>.
     * 
     * @param main
     * 		entity bean principale
     * @param newValues
     * 		entity bean che contiene i nuovi valori
     * @param cols
     * 		nomi delle colonne da copiare
     * @return
     * 		entity bean principale con i nuovi attributi
     * @throws Exception
     * 		in caso di errore
     */
    public static Object copyAttributes(Object main, Object newValues, Set<String> cols) throws Exception {
       	if (main==null || newValues==null) return main;
       	
       	Map<String,Object> values=BeanUtil.getPropertyValues(newValues, cols);       	
       	BeanUtil.setPropertyValues(main, values);    	

    	return main;
    }
}
